package com.lfs.admin.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lfs.admin.config.MinioConfig;
import com.lfs.base.util.StringUtils;
import io.minio.*;
import io.minio.messages.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统数据初始化
 */
@Slf4j
//@Component
public class MinioConfigInit implements ApplicationRunner {

    @Autowired
    private MinioConfig minioConfig;

    @Autowired
    private MinioClient client;

    /**
     * 桶占位符
     */
    private static final String BUCKET_PARAM = "${bucket}";

    /**
     * bucket权限-只读
     * {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:GetBucketLocation","s3:ListBucket"],"Resource":["arn:aws:s3:::qsdi1"]},{"Effect":"Allow","Principal":{"AWS":["*"]},"Action":["s3:GetObject"],"Resource":["arn:aws:s3:::qsdi1/*"]}]}
     */
    private static final String READ_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";


    /**
     * 启动服务更新redis缓存
     *
     * @param args
     * @throws Exception
     */
    @Override
    public void run(ApplicationArguments args) {
        //创建bukect
        createBucket();
        //生命周期配置
        lifecycleConfig();
    }

    /**
     * 创建桶
     */
    private void createBucket() {
        log.info("************Minio桶初始化开始************");
        try {
            String[] bucketArr = minioConfig.getBucketName().split(",");
            for (String bucketName : bucketArr) {
                // 检查文件夹是否已经存在
                boolean isExist = client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
                if (!isExist) {
                    log.info("************Minio桶{}初始化创建************", bucketName);
                    client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                    log.info("************Minio桶{}初始化创建完成************", bucketName);
                }
                // 获取访问策略
                String policy = client.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());
                // 访问策略为空时，设置访问策略
                if (StringUtils.isEmpty(policy)) {
                    // 设置访问策略
                    SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder().bucket(bucketName)
                            .config(READ_ONLY.replace(BUCKET_PARAM, bucketName)).build();
                    client.setBucketPolicy(setBucketPolicyArgs);
                }
            }
            log.info("************Minio桶初始化结束************");
        } catch (Exception e) {
            log.error("************Minio桶初始化失败************", e);
        }
    }


    /**
     * 生命周期配置
     */
    public void lifecycleConfig() {
        log.info("************Minio桶生命周期配置开始************");
        deleteLifecycle();
        setLifecycle();
        log.info("************Minio桶生命周期配置结束************");
    }

    /**
     * 设置生命周期
     */
    private void setLifecycle() {
        try {
            String lifecycle = minioConfig.getBucketLifecycle();
            if (StringUtils.isEmpty(lifecycle)) {
                return;
            }
            JSONObject lifecycleJO = JSON.parseObject(lifecycle);

            lifecycleJO.forEach((bucket, ja) -> {
                try {
                    boolean isExist = client.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
                    if (isExist) {
                        List<LifecycleRule> rules = new LinkedList<>();
                        for (Object config : (JSONArray) ja) {
                            String id = ((JSONObject) config).getString("id");
                            if (StringUtils.isEmpty(id)) {
                                id = UUID.randomUUID().toString().replace("-", "");
                            }
                            String status = ((JSONObject) config).getString("status");
                            Integer days = ((JSONObject) config).getJSONObject("expiration").getInteger("days");
                            String prefix = ((JSONObject) config).getJSONObject("filter").getString("prefix");
                            rules.add(
                                    new LifecycleRule(
                                            Status.fromString(status),
                                            null,
                                            new Expiration((ZonedDateTime) null, days, null),//1天后删除
                                            new RuleFilter(prefix),
                                            id,
                                            null,
                                            null,
                                            null));
                        }
                        log.info("************Minio桶{}生命周期设置************", bucket);
                        client.setBucketLifecycle(SetBucketLifecycleArgs.builder().bucket(bucket).config(new LifecycleConfiguration(rules)).build());
                    } else {
                        log.error("桶:{}不存在", bucket);
                    }
                } catch (Exception e) {
                    log.error("设置桶:{}生命周期发生错误:{}", bucket, e.getMessage());
                }
            });
        } catch (Exception e) {
            log.error("************Minio桶生命周期配置失败************", e);
        }
    }

    /**
     * 移除配置文件中没有配置 的 桶生命周期配置
     */
    private void deleteLifecycle() {
        String lifecycle = minioConfig.getBucketLifecycle();

        //存放已创建 且 不在配置文件中的 桶名称
        final List<String> deleteList = new ArrayList<String>();
        try {
            List<Bucket> bucketList = client.listBuckets();
            if (StringUtils.isEmpty(lifecycle)) {
                if (bucketList != null) {
                    deleteList.addAll(bucketList.stream().map(Bucket::name).collect(Collectors.toList()));
                }
            } else {
                if (bucketList != null) {
                    JSONObject lifecycleJO = JSON.parseObject(lifecycle);
                    Set<String> bucketNameSets = lifecycleJO.keySet();
                    bucketList.forEach(bucket -> {
                        if (!bucketNameSets.contains(bucket.name())) {
                            deleteList.add(bucket.name());
                        }
                    });
                }
            }
            for (String bucket : deleteList) {
                if (client.getBucketLifecycle(GetBucketLifecycleArgs.builder().bucket(bucket).build()) == null) {
                    continue;
                }
                log.info("************Minio移除桶{}生命周期配置************", bucket);
                client.deleteBucketLifecycle(DeleteBucketLifecycleArgs.builder().bucket(bucket).build());
                ;
            }
        } catch (Exception e) {
            log.error("************Minio删除桶生命周期配置失败************", e);
        }
    }
}
